JAX Blog

Chaos Monkey für Spring Boot

Bewusstes Chaos mit Spring Boot Power

Aug 15, 2023

Mit Chaos Engineering wird bewusst Chaos in ein System eingeführt, um dessen Reaktion auf unvorhergesehene Ereignisse zu testen und Schwachstellen aufzudecken. Der „Chaos Monkey for Spring Boot“ ist eine populäre Implementierung für Chaos Engineering in Spring-Boot-Anwendungen. Es ist ein leistungsfähiges Werkzeug, das die Robustheit von Spring-Boot-Anwendungen durch die gezielte Einführung von Chaostests verbessert.

Chaos Monkey for Spring Boot [1] ermöglicht es Entwicklern, Ausfallszenarien zu simulieren und die Reaktion ihres Systems darauf zu überwachen. Dadurch können potenzielle Schwachstellen identifiziert und Engpässe aufgedeckt werden, um die Stabilität und Ausfallsicherheit der Anwendung zu verbessern. Beispielsweise ermöglicht Chaos Monkey den Entwicklern das plötzliche Abschalten eines Dienstes, Netzwerkstörungen oder die Simulation hoher Lasten auf das System. Durch diese gezielte Einführung von Chaostests und die Behebung der Schwachstellen ist sichergestellt, dass ihre Anwendung auch unter schwierigen Bedingungen zuverlässig funktioniert. Der Chaos Monkey for Spring Boot bietet zahlreiche Funktionalitäten und Konfigurationsoptionen, um den Testprozess zu steuern und die gewünschten Szenarien zu simulieren. Dieser Artikel bietet einen detaillierten Einblick in den Chaos Monkey for Spring Boot. Darüber hinaus werden seine Einsatzszenarien, Best Practices und Implementierungsmöglichkeiten diskutiert.

NEUES AUS DER JAVA-ENTERPRISE-WELT

Serverside Java-Track entdecken

 

Vorstellung

Das Projekt Chaos Monkey for Spring Boot wurde ursprünglich anno 2017 von Benjamin Wilms bei codecentric ins Leben gerufen und über die Jahre von ihm und seinen Kollegen weiterentwickelt. Das Projekt wird aktiv gepflegt und an neue Spring-Boot-Versionen angepasst. Inspiriert von den Principles of Chaos Engineering [2] und mit einem Fokus auf Spring Boot bietet das Chaos-Monkey-Projekt eine Möglichkeit, Anwendungen besser zur Laufzeit zu testen. Das kann lokal, aber auch in der Cloud geschehen. Die Fragen, die sich jeder Entwickler stellt, egal wie viele Unit- und Integrationstests existieren: Wie verhält sich unsere Anwendung im Betrieb? Was passiert bei langsamen Datenbankabfragen? Wie verhält sich die Anwendung bei langsamen Antworten oder Fehlern anderer Services? Was passiert, wenn Discovery Service oder Discovery Client Fehler produzieren? Oder sogar zu viel Speicher oder CPU verbrauchen? Um all diese Probleme zu simulieren und Störungen zu injizieren, unterstützt uns nun der Chaos Monkey.

Implementierung und Konfiguration

Es gibt zwei Möglichkeiten, Chaos Monkey for Spring Boot in einer bestehenden Spring-Boot-Anwendung zu aktivieren. Entweder fügt man ihn zu den regulären Anwendungsabhängigkeiten im Build- und Dependency-Management-Tool hinzu (Listing 1) oder man bindet ihn als externe Abhängigkeit beim Start der Spring-Boot-Anwendung ein. Da sich das Tool nicht im offiziellen Release-Train von Spring Boot befindet, muss die passende Version selbst definiert werden.

// Maven
<dependency>
  <groupId>de.codecentric</groupId>
  <artifactId>chaos-monkey-spring-boot</artifactId>
  <version>3.0.1</version>
</dependency>
 
// Gradle
plugins {
  id 'java'
  id 'org.springframework.boot' version '3.0.1'
  id 'io.spring.dependency-management' version '1.1.0'
}

Beim Start der Spring-Boot-Anwendung mit aktiviertem „chaos-monkey“-Profil wird die Funktionalität für die ausgewählten Watchers aktiv. Die Eigenschaften können über Umgebungsvariablen, System Properties oder Application Properties konfiguriert werden (Listing 2). Die Konfiguration über Properties bietet alle verfügbaren Optionen, erfordert aber einen Neustart, um Änderungen zu übernehmen. Um das zu vermeiden, können die Konfiguration über Actuator REST API vorgenommen werden.

spring.profiles.active=chaos-monkey
chaos.monkey.enabled=true
management.endpoints.web.exposure.include=health,info,chaosmonkey
 
chaos.monkey.watcher.service=true
chaos.monkey.assaults.latencyActive=true

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Chaos Monkey Watchers und Assaults

Ein Watcher ist eine Komponente von Chaos Monkey for Spring Boot, die die Anwendung nach Spring Beans durchsucht. Je nach Konfiguration werden Annotation Watchers (Abb. 1) z. B. für @Component, Actuator Watchers und Outgoing Request Watchers z. B. für RestTemplate und WebClient registriert. Der Alternative Bean Watcher verwendet im Gegensatz zu den anderen Watchers ausschließlich den Bean-Namen. Mit Hilfe von Spring AOP wird ein Proxy für die Watcher-Funktionalität zur Verfügung gestellt. Beim Aufruf einer öffentlichen Methode auf einer Watched Bean entscheidet dann der Chaos Monkey, ob ein Angriff oder eben keine Aktion ausgeführt wird. Dieses Verhalten kann durch die Konfiguration beeinflusst werden.

Abb. 1: Annotation Watchers und Assaults

Assaults sind das Kernelement von Chaos Monkey und ihre Anwendung erfolgt je nach Konfiguration. Es gibt verschiedene Arten von Assaults: Request Assaults greifen spezifische Punkte der Anwendung an und können Latenz oder Exceptions verursachen. Runtime Assaults hingegen greifen die gesamte Anwendung an und können diese sogar zum Absturz bringen (AppKiller Assault). Möglich ist auch, nur den Speicher (Memory Assault) oder die CPU (CPU Assault) der Java Virtual Machine anzugreifen. Dank Chaos Monkey for Spring Boot können alle Arten von Runtime Exceptions geworfen und die benötigten Exceptions zur Laufzeit konfiguriert werden. Die Runtime Assaults können entweder durch Scheduling oder durch Chaos Monkey Endpoints ausgelöst werden.

Konfiguration des Chaos Monkey

Essenziell im Umgang ist, dass eine Änderung der Watcher-Konfiguration stets einen Neustart der Anwendung zur Folge hat. Das liegt an der Proxy-basierten Implementierung des Tools. Daher muss die gewünschte Konfiguration folglich bereits beim Start der Anwendung festgelegt werden. Jedoch können Watchers via Spring Boot Actuators auch später noch zur Laufzeit umkonfiguriert werden. Da es Spring Boot mittels des Actuators ferner ermöglicht, diese über JMX auszulesen bzw. anzupassen, bietet der Chaos Monkey diese Funktionalität auch für die Konfiguration an.

Welche Spring Beans benötigen nun gegenwärtig einen Watcher? In vielen Fällen ist ein Watcher für Service-Komponenten ausreichend. Runtime Exceptions werden z. B. durch die Spring-Data-Implementierung geworfen und erst im Web-Layer als Fehler an den Aufrufer zurückgegeben. Ob nun die Data Access Exception im Repository oder im Service durch den Assault erzeugt wird, ist in diesem Fall nicht relevant. Sollte der Service jedoch Fallback-Strategien implementieren, wäre die Repository-Schicht vorzuziehen (Listing 3).

#spring.profiles.active=chaos-monkey
 
management.endpoint.chaosmonkey.enabled=true
management.endpoint.chaosmonkeyjmx.enabled=false
 
chaos.monkey.watcher.controller=false
chaos.monkey.watcher.restController=false
chaos.monkey.watcher.service=true
chaos.monkey.watcher.repository=false
chaos.monkey.watcher.component=false
chaos.monkey.watcher.beans=<List of bean names>
chaos.monkey.watcher.exclude=<List of class names>

Wie zuvor erwähnt, erfolgt die Konfiguration der Assaults fortan über den Actuator Endpoint. Dies ermöglicht auch die Ausführung von Chaostests in einer CI/CD Pipeline. Folgende Beispiele zeigen mögliche Problemfälle. Die in Listing 4 gezeigte Konfiguration erzeugt zufällige Runtime Exceptions mit dem Exception Assault. Der Assault-Level in der Konfiguration definiert, wie viele Requests angegriffen werden sollen. In unserem Beispiel ist das jeder fünfte. Ob nun eine normale Runtime Exception oder eine andere ausgelöst werden soll, kann konfiguriert werden.

curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \
-H 'Content-Type: application/json' \
-d \
‘
{
  "level": 5,
  "latencyActive": false,
  "exceptionsActive": true,
  "killApplicationActive": false
}’

Im nächsten Beispiel (Listing 5) wird der AppKill Assault konfiguriert. Dieser kann über eine CronExpression oder einen Actuator-Aufruf ausgelöst werden.

curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \
-H 'Content-Type: application/json' \
-d \
‘
{
  "latencyActive": false,
  "exceptionsActive": false,
  "killApplicationActive": true,
  "killApplicationExpression": "*/1 * * * * ?"
}'

Im letzten Beispiel (Listing 6) sollen hängende Threads simuliert werden. Das Hinzufügen einer zusätzlichen Latenz von 100 s bei jeder Antwort (Level 1) führt dazu, dass die Anwendung nicht mehr reagiert.

curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \
-H ‘Content-Type: application/json’ \
-d \
‘
{
  "level": 1,
  "latencyRangeStart": 99999,
  "latencyRangeEnd": 100000,
  "latencyActive": true,
  "killApplicationActive": false,
  "exceptionsActive": false
}

Das sind nur drei Beispiele, die verschiedene Konfigurationen aufzeigen. Darüber hinaus existieren noch unzählige weitere Möglichkeiten – der Kreativität sind keine Grenzen gesetzt. Sind die Experimente einmal definiert und konfiguriert, kann man mit einem Tool wie Gatling [3] oder dem Chaos Toolkit [4] Tests durchführen und die Reports und Metriken analysieren.

SIE LIEBEN JAVA?

Den Core-Java-Track entdecken

 

Metriken der Attacken

Die Chaos-Monkey-Metriken sind über das Spring Boot Actuator API und Micrometer [5] verfügbar. Damit können die gesammelten Metriken für die Chaostests aus der Anwendung extrahiert werden (Listing 7). Diese Metriken bieten wertvolle Einblicke in das Verhalten der Anwendung während der Chaostests. Sie ermöglichen es Entwicklern, die Auswirkungen der verschiedenen Angriffe auf Performance, Latenz, Speicherverbrauch und andere wichtige Aspekte zu überwachen und zu analysieren. Der Einsatz von Chaos-Monkey-Metriken ermöglicht es Entwicklern, die Auswirkungen von Störungen und Unregelmäßigkeiten auf die Anwendung besser zu verstehen und gezielte Optimierungen vorzunehmen. Außerdem ist es möglich, die Metriken einzusetzen, um die Effektivität der implementierten Resilienz-Patterns zu bewerten und potenzielle Schwachstellen zu identifizieren.

curl -X GET http://localhost:8080/actuator/metrics \
-H 'Content-Type: application/json'
 
#Application Metrics
chaos_monkey_application_request_count_total
chaos_monkey_application_request_count_assaulted
#Assault Exception
chaos_monkey_assault_exception_count
#Assault Latency
chaos_monkey_assault_latency_count_gauge
chaos_monkey_assault_latency_count_total
#Assault KillApp
chaos_monkey_assault_killapp_count
#Watcher Metrics
chaos_monkey_assault_component_watcher_total
chaos_monkey_assault_controller_watcher_total

Patterns für die Behebung der Schwachstellen

In einer verteilten Architektur, in der verschiedene Services miteinander kommunizieren, treten oftmals unvermeidbare Fehler und Störungen auf. Resilience Patterns [6] dienen dazu, diese Fehler abzufangen, abzuschwächen und die Gesamtstabilität des Systems zu gewährleisten. Ein häufig verwendetes Pattern ist das Circuit Breaker Pattern. Dieses unterbricht die Kommunikation mit einem Dienst, falls dieser nicht ordnungsgemäß funktioniert, und stattdessen Fehlerbehandlungsmechanismen einsetzt. Das Fallback Pattern stellt alternativ Funktionalität oder Daten bereit, sofern ein Dienst nicht verfügbar ist. Retry Patterns ermöglichen das erneute Senden von Anfragen, wenn diese aufgrund von temporären Netzwerkproblemen fehlschlagen. Das Timeout Pattern definiert maximale Zeitlimits für Anfragen, um lange Wartezeiten zu vermeiden und die Reaktionsfähigkeit des Systems zu gewährleisten. Das Bulkhead Pattern und das Rate-Limiter Pattern sind weitere wichtige Resilience Patterns. Sie zielen darauf ab, die Auswirkungen von Fehlern in einem Dienst zu begrenzen. Daneben schützen sie andere Teile des Systems vor Ausfällen, indem sie Ressourcen isolieren und in separate Pools aufteilen. Durch den Einsatz dieser und weiterer Resilience Patterns können Microservices optimaler auf unvorhergesehene Situationen reagieren, Ausfälle isolieren und eine höhere Verfügbarkeit und Ausfallsicherheit erreichen. Die effektive Anwendung dieser Patterns ist entscheidend, um die Zuverlässigkeit des gesamten Microservices-Ökosystems zu gewährleisten.

Die Bibliothek Resilience4j [7] bietet umfassende Unterstützung für die Implementierung von Resilience Patterns in Microservices und lässt sich nahtlos in Spring-Boot-Anwendungen integrieren. Durch die Integration mit Spring Boot können Entwickler die Funktionalität von Resilience4j nutzen, indem sie kurzerhand die entsprechenden Abhängigkeiten und Konfigurationen hinzufügen. Die Resilience4j Annotations und Wrapper erleichtern die Anwendung der Resilience Patterns auf Spring-Boot-Komponenten wie Services, Controller oder Repository-Klassen. Ferner ermöglicht die Integration mit Spring Boot die Verwendung von Spring Boot Actuator zur Überwachung und Erfassung von Metriken für die Resilience Patterns. Infolgedessen können Entwickler das Verhalten ihrer Microservices in Bezug auf Fehlertoleranz und Resilienz effektiv überwachen und analysieren. Die nahtlose Integration erleichtert Entwicklern die Implementierung einer robusten und widerstandsfähigen Architektur in ihren Microservices.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Fazit

Chaos Monkey for Spring Boot ist ein sehr nützliches Werkzeug für alle Softwareentwickler, die sich mit Chaos Engineering beschäftigen möchten. Durch die Implementierung mit Spring AOP Proxies können Seiteneffekte innerhalb der Anwendung simuliert werden, ohne die reale Infrastruktur zu beeinflussen. Dies ermöglicht es Entwicklern, Probleme auf einfache Weise zu simulieren und zu reproduzieren, sogar auf ihren eigenen Computern. Sobald man damit beginnt, Chaosexperimente zu definieren, wird deutlich, dass zunächst normalerweise das Monitoring verbessert werden muss, um die auftretenden Probleme zu identifizieren. Anschließend werden typische Resilienz-Patterns verwendet, um die entdeckten Schwachstellen zu beheben. Chaos Monkey for Spring Boot erleichtert also nicht nur das Experimentieren mit Chaos, sondern unterstützt auch die Entwicklung resilienter Anwendungen.


Links & Literatur

[1] Chaos Engineering for Spring Boot: https://github.com/codecentric/chaos-monkey-spring-boot

[2] Principles of Chaos Engineering: https://principlesofchaos.org

[3] Gatling: https://gatling.io

[4] Chaos Toolkit: https://chaostoolkit.org

[5] Micrometer: https://micrometer.io

[6] Resilience Patterns: https://github.com/lucasnscr/Resilience-Patterns

[7] https://resilience4j.readme.io/docs

Alle News der Java-Welt:

Behind the Tracks

Agile, People & Culture
Teamwork & Methoden

Clouds & Kubernetes
Alles rund um Cloud

Core Java & Languages
Ausblicke & Best Practices

Data & Machine Learning
Speicherung, Processing & mehr

DevOps & CI/CD
Deployment, Docker & mehr

Microservices
Strukturen & Frameworks

Performance & Security
Sichere Webanwendungen

Serverside Java
Spring, JDK & mehr

Software-Architektur
Best Practices

Web & JavaScript
JS & Webtechnologien

Digital Transformation & Innovation
Technologien & Vorgehensweisen

Domain-driven Design
Grundlagen und Ausblick

Spring Ecosystem
Wissen in Spring-Technologien

Web-APIs
API-Technologie, Design und Management